﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using for7raid.vk;
using System.Windows;
using System.Diagnostics;
using System.Windows.Input;
using System.Threading.Tasks;
using System.Xml;
using System.Windows.Data;
using System.ComponentModel;

namespace for7raid.vkGroupExplorer
{
    public class MainWindowViewModel : DependencyObject, INotifyPropertyChanged
    {
        #region Properties
        public static bool GetIsSelected(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsSelectedProperty);
        }

        public static void SetIsSelected(DependencyObject obj, bool value)
        {
            obj.SetValue(IsSelectedProperty, value);
        }
        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.RegisterAttached("IsSelected", typeof(bool), typeof(MainWindowViewModel), new UIPropertyMetadata(false));


        public static bool GetIsUserMemeber(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsUserMemeberProperty);
        }

        public static void SetIsUserMemeber(DependencyObject obj, bool value)
        {
            obj.SetValue(IsUserMemeberProperty, value);
        }
        public static readonly DependencyProperty IsUserMemeberProperty =
            DependencyProperty.RegisterAttached("IsUserMemeber", typeof(bool), typeof(MainWindowViewModel), new UIPropertyMetadata(false));



        public ObservableCollection<User> Friends
        {
            get { return (ObservableCollection<User>)GetValue(FriendsProperty); }
            set { SetValue(FriendsProperty, value); }
        }

        public static readonly DependencyProperty FriendsProperty =
            DependencyProperty.Register("Friends", typeof(ObservableCollection<User>), typeof(MainWindowViewModel), new UIPropertyMetadata(null));


        public ObservableCollection<Group> Groups
        {
            get { return (ObservableCollection<Group>)GetValue(GroupsProperty); }
            set { SetValue(GroupsProperty, value); }
        }

        public static readonly DependencyProperty GroupsProperty =
            DependencyProperty.Register("Groups", typeof(ObservableCollection<Group>), typeof(MainWindowViewModel), new UIPropertyMetadata(null));



        public List<User> UserIntersection
        {
            get { return (List<User>)GetValue(UserIntersectionProperty); }
            set { SetValue(UserIntersectionProperty, value); }
        }

        public static readonly DependencyProperty UserIntersectionProperty =
            DependencyProperty.Register("UserIntersection", typeof(List<User>), typeof(MainWindowViewModel), new UIPropertyMetadata(new List<User>()));


        public ObservableCollection<City> Cities
        {
            get { return (ObservableCollection<City>)GetValue(CitiesProperty); }
            set { SetValue(CitiesProperty, value); }
        }

        public static readonly DependencyProperty CitiesProperty =
            DependencyProperty.Register("Cities", typeof(ObservableCollection<City>), typeof(MainWindowViewModel), new UIPropertyMetadata(new ObservableCollection<City>()));

        public User SelectedUser
        {
            get { return (User)GetValue(SelectedUserProperty); }
            set { SetValue(SelectedUserProperty, value); }
        }

        public static readonly DependencyProperty SelectedUserProperty =
            DependencyProperty.Register("SelectedUser", typeof(User), typeof(MainWindowViewModel), new UIPropertyMetadata(null));


        public int FindUserGroupsCount
        {
            get { return (int)GetValue(FindUserGroupsCountProperty); }
            set { SetValue(FindUserGroupsCountProperty, value); }
        }

        public static readonly DependencyProperty FindUserGroupsCountProperty =
            DependencyProperty.Register("FindUserGroupsCount", typeof(int), typeof(MainWindowViewModel), new UIPropertyMetadata(0));
        
        #endregion

        #region Commands

        public static ICommand UpdateFriendCommand { get; set; }
        public static ICommand UpdateGroupCommand { get; set; }
        public static ICommand FindUserIntersectionCommand { get; set; }
        public static ICommand GotoUriCommand { get; set; }
        public static ICommand SelectAllCommand { get; set; }
        public static ICommand SelectNoneCommand { get; set; }
        public static ICommand FindUserGroupsCommand { get; set; }
        public static ICommand AddUsersCommand { get; set; }
        public static ICommand AddGroupsCommand { get; set; }
        #endregion


        #region Вспомогательные свойства
        public List<Group> SelectedGroups
        {
            get { return Groups.Where(g => GetIsSelected(g)).ToList(); }
        }

        public List<User> SelectedFriends
        {
            get { return Friends.Where(g => GetIsSelected(g)).ToList(); }
        }

        public City SelectedCity
        {
            set
            {
                var view = CollectionViewSource.GetDefaultView(UserIntersection);
                view.Filter = delegate(object item) { return value.Id == 0 || (item as User).City == value.Id.ToString() || (value.Id == -1 && string.IsNullOrEmpty((item as User).City)); };
            }
        }

        #endregion

        public MainWindowViewModel()
        {
            Login();
            BindCommands();

            //GetCities();

#if DEBUG
            UpdateFriendList();
            UpdateGroupList();
#endif

        }

        private void GetAllCities()
        {
            Cities.Clear();
            Cities.Add(new City() { Id = 0, Name = "(Все)" });
            Cities.Add(new City() { Id = -1, Name = "(Без города)" });

            for (int k = 0; k < 25; k++)
            {
                vkConnector.General.GetCities(Enumerable.Range(k * 1000, 1000).ToArray()).ExecAsync(doc =>
                {
                    City.FromResponse(doc).ForEach(c => Cities.Add(c));

                });
            }

        }

        private void GetCitiesForUsers()
        {
            Cities.Clear();
            Cities.Add(new City() { Id = 0, Name = "(Все)" });
            Cities.Add(new City() { Id = -1, Name = "(Без города)" });


            var citiesIds = UserIntersection.Where(i => !string.IsNullOrEmpty(i.City)).Select(u => int.Parse(u.City)).Distinct();
            if (citiesIds.Any())
            {
                vkConnector.General.GetCities(citiesIds.ToArray()).ExecAsync(doc =>
                    {
                        City.FromResponse(doc).ForEach(c => Cities.Add(c));

                    });
            }
        }

        private static void Login()
        {
            try
            {
                vkConnector.vkConnector.Login(2449153, 0
                    //+ 8 //audio
                     + 2 //friends
                    //+ 8192 //wall
                     + 262144 //groups
                     );
            }
            catch (Exception)
            {

                Application.Current.Shutdown();
            }
            try
            {
                vkConnector.User.WhoAmIEx().ExecAsync(
                        doc =>
                        {


                            User.Me = User.MeFromResponseEx(doc);

                            Debug.WriteLine("Загружен свой профиль");
                        }
                        );
            }
            catch (Exception ex)
            {

                MessageBox.Show("Не могу получить свой профиль", "вРитме - Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void BindCommands()
        {



            UpdateFriendCommand = new for7raid.Control.SimpleCommand(p => { UpdateFriendList(); });
            UpdateGroupCommand = new for7raid.Control.SimpleCommand(p => { UpdateGroupList(); });
            FindUserIntersectionCommand = new for7raid.Control.SimpleCommand(p => { FindUserIntersection(); });
            GotoUriCommand = new for7raid.Control.SimpleCommand(p => { Process.Start((p as Uri).ToString()); });
            FindUserGroupsCommand = new for7raid.Control.SimpleCommand(p => { FindUserGroups(); });

            AddUsersCommand = new for7raid.Control.SimpleCommand(p => { AddUsers(); });
            AddGroupsCommand = new for7raid.Control.SimpleCommand(p => { AddGroups(); });

            SelectAllCommand = new for7raid.Control.SimpleCommand(p => { SelectAll(p as IEnumerable<DependencyObject>); });
            SelectNoneCommand = new for7raid.Control.SimpleCommand(p => { SelectNone(p as IEnumerable<DependencyObject>); });


        }

        private void AddUsers()
        {
            var box = new for7raid.Utils.InputBox();
            if (box.ShowDialog() == true)
            {
                System.Windows.Input.Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
                var usersId = box.Message.Text;
                try
                {
                    for7raid.vkConnector.User.GetProfiles(usersId).ExecAsync(doc =>
                               {
                                   var users = User.FromResponse(doc);
                                   users.ForEach(u => Friends.Insert(0, u));
                                   System.Windows.Input.Mouse.OverrideCursor = null;
                               }
                               );
                }
                catch
                {
                    System.Windows.Input.Mouse.OverrideCursor = null;

                }
            }
        }

        private void AddGroups()
        {
            var box = new for7raid.Utils.InputBox();
            if (box.ShowDialog() == true)
            {
                System.Windows.Input.Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
                var gids = box.Message.Text;
                try
                {
                    for7raid.vkConnector.Group.GetByIds(gids).ExecAsync(doc =>
                    {
                        var groups = Group.FromResponse(doc);
                        groups.ForEach(u => Groups.Insert(0, u));
                        System.Windows.Input.Mouse.OverrideCursor = null;
                    }
                               );
                }
                catch
                {
                    System.Windows.Input.Mouse.OverrideCursor = null;

                }
            }
        }

        private void SelectAll(IEnumerable<DependencyObject> iEnumerable)
        {
            foreach (var item in iEnumerable)
            {
                SetIsSelected(item, true);
            }
        }

        private void SelectNone(IEnumerable<DependencyObject> iEnumerable)
        {
            foreach (var item in iEnumerable)
            {
                SetIsSelected(item, false);
            }
        }

        private void FindUserIntersection()
        {

            try
            {

                UserIntersection = null;

                var groups = SelectedGroups;


                //получим список пользователей групп
                Action<object> getUsers = (object m) =>
                {
                    var item = m as Group;
                    item.Users = new List<int>();

                    int i = 0;
                    bool cont = true;
                    while (cont && i < 1500)
                    {
                        var listCont = for7raid.vkConnector.Group.GetMembers(item.ID, i * 1000).Exec().SelectNodes("/response/users/uid").OfType<XmlNode>().Select(n => n.ParseXmlNodeAsInt()).ToList();
                        listCont.ForEach(user => item.Users.Add(user));
                        cont = listCont.Count == 1000;
                        i++;
                    }

                    Debug.WriteLine("{0}: {2}", item.ID, item.Name, item.Users.Count);



                };


                Action findInter = () =>
                    {
                        List<int> intersection = groups[0].Users;
                        for (int i = 1; i <= groups.Count - 1; i++)
                        {
                            intersection = intersection.Intersect(groups[i].Users).AsParallel().ToList();
                        }

                        if (intersection.Count > 0)
                        {
                            vkConnector.User.GetProfiles(intersection.Take(500).Select(i => i.ToString()).ToArray()).ExecAsync(doc =>
                            {
                                UserIntersection = User.FromResponse(doc);
                                GetCitiesForUsers();

                            });
                        }
                        else
                            ClearValue(UserIntersectionProperty);
                    };

                Action<Task[]> gotUsers = (Task[] ts) =>
                {


                    //мука с потоками, это поток задач, нужно остальное все делать в основном потоке приложения, т.к. там еще запрос асинхронный то
                    Dispatcher.BeginInvoke(
                        (Action)delegate()
                        {
                            findInter();

                        });
                };

                Task[] tasks = groups.Where(g => g.Users == null || g.Users.Count == 0).Select(g => Task.Factory.StartNew(getUsers, g)).ToArray();
                if (tasks.Any())
                    Task.Factory.ContinueWhenAll(tasks, gotUsers);
                else
                    findInter();


            }
            catch (Exception ex)
            {

                MessageBox.Show("Не могу получить список", "GroupExplorer - Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
                ClearValue(UserIntersectionProperty);
            }
        }

        private void UpdateFriendList()
        {
            try
            {

                Friends = null;

                vkConnector.User.GetMyFriends().ExecAsync(doc =>
                {

                    Friends = new ObservableCollection<User>( User.FromResponse(doc));
                    Friends.Insert(0, User.Me);

                });

            }
            catch (Exception ex)
            {

                MessageBox.Show("Не могу получить список друзей", "GroupExplorer - Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
                ClearValue(FriendsProperty);
            }
        }

        private void UpdateGroupList()
        {
            try
            {

                Groups = null;

                vkConnector.User.GetMyGroups().ExecAsync(doc =>
                {
                    Groups = new ObservableCollection<Group>( Group.FromResponse(doc));
                });

            }
            catch (Exception ex)
            {

                MessageBox.Show("Не могу получить список групп", "GroupExplorer - Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
                ClearValue(GroupsProperty);
            }
        }

        private void FindUserGroups()
        {
            System.Windows.Input.Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;

            //Снимем со всех групп отметку, что это пользователь группы
            Groups.ToList().ForEach(g => SetIsUserMemeber(g, false));

            var userId = SelectedUser.uid;

            //прогнать по группам и найти в которых пользователь состоит
            var groups = Groups.Where(g => GetIsSelected(g)).ToList();
            groups.ForEach(g => SetIsUserMemeber(g, Group.FromResponseIsMember(for7raid.vkConnector.Group.GetIsMember(g.ID.ToString(), userId).Exec())));

            
            Groups = new ObservableCollection<Group>( Groups.OrderBy(g => !GetIsUserMemeber(g)));
            //foreach (var gr in Groups)
            //{
            //    SetIsSelected(gr, false);
            //}

            FindUserGroupsCount = Groups.Where(g => GetIsUserMemeber(g)).Count();

            System.Windows.Input.Mouse.OverrideCursor = null;

        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string Name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(Name));
        }
    }
}
